package edu.ncsu.csc.itrust.action;

import java.util.Calendar;
import java.util.Date;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.List;
import junit.framework.TestCase;
import edu.ncsu.csc.itrust.beans.DiagnosisBean;
import edu.ncsu.csc.itrust.beans.Email;
import edu.ncsu.csc.itrust.beans.HospitalBean;
import edu.ncsu.csc.itrust.beans.LabProcedureBean;
import edu.ncsu.csc.itrust.beans.MedicationBean;
import edu.ncsu.csc.itrust.beans.OfficeVisitBean;
import edu.ncsu.csc.itrust.beans.OverrideReasonBean;
import edu.ncsu.csc.itrust.beans.PatientReferralBean;
import edu.ncsu.csc.itrust.beans.PrescriptionBean;
import edu.ncsu.csc.itrust.beans.ProcedureBean;
import edu.ncsu.csc.itrust.beans.forms.EditOfficeVisitForm;
import edu.ncsu.csc.itrust.dao.DAOFactory;
import edu.ncsu.csc.itrust.dao.mysql.LabProcedureDAO;
import edu.ncsu.csc.itrust.dao.mysql.OfficeVisitDAO;
import edu.ncsu.csc.itrust.dao.mysql.OfficeVisitDiagnosisDAO;
import edu.ncsu.csc.itrust.dao.mysql.OfficeVisitLabProcedureDAO;
import edu.ncsu.csc.itrust.dao.mysql.OfficeVisitMedicationDAO;
import edu.ncsu.csc.itrust.dao.mysql.OfficeVisitProcedureDAO;
import edu.ncsu.csc.itrust.dao.mysql.PatientReferralDAO;
import edu.ncsu.csc.itrust.datagenerators.TestDataGenerator;
import edu.ncsu.csc.itrust.exception.DBException;
import edu.ncsu.csc.itrust.exception.FormValidationException;
import edu.ncsu.csc.itrust.exception.iTrustException;
import edu.ncsu.csc.itrust.testutils.EvilDAOFactory;
import edu.ncsu.csc.itrust.testutils.TestDAOFactory;

public class EditOfficeVisitActionTest extends TestCase {
	private DAOFactory factory = TestDAOFactory.getTestInstance();
	private TestDataGenerator gen = new TestDataGenerator();
	private EditOfficeVisitAction action;
	private EditPrescriptionAction action2;
	private EditOfficeVisitAction action3;
	private EditPrescriptionAction action4;
	
	@Override
	protected void setUp() throws Exception {
		gen.clearAllTables();
		gen.hospitals();
		gen.hcp0();
		gen.patient1();
		gen.admin1();
		gen.officeVisit1();
		gen.ndCodes();
			
		action = new EditOfficeVisitAction(factory, 9000000001L, "1", "1");
		action2 = new EditPrescriptionAction(factory);
	}
	
	public void testOVID() {
		try {
			action = new EditOfficeVisitAction(factory, 0l, "1", "NaN");
			fail("exception should have been thrown");
		} catch (iTrustException e) {
			assertEquals("Office Visit ID is not a number: For input string: \"NaN\"", e.getMessage());
		}
	}
	
	public void testEvilDatabase() {
		try {
			action = new EditOfficeVisitAction(EvilDAOFactory.getEvilInstance(), 0l, "1", "1");
			fail("exception should have been thrown");
		} catch (iTrustException e) {
			assertEquals(
						 "A database exception has occurred. Please see the log in the console for stacktrace", e
						 .getMessage());
			DBException dbe = (DBException) e;
			assertEquals(EvilDAOFactory.MESSAGE, dbe.getSQLException().getMessage());
		}
	}
	
	public void testOVDoesntExist() {
		try {
			action = new EditOfficeVisitAction(TestDAOFactory.getTestInstance(), 0l, "1", "158");
			fail("exception should have been thrown");
		} catch (iTrustException e) {
			assertEquals("Office Visit 158 with Patient MID 1 does not exist", e.getMessage());
		}
	}
	
	public void testGetHospitals() throws Exception {
		List<HospitalBean> hospitals = action.getHospitals(9000000000L);
		assertEquals(4, hospitals.size());
		assertEquals("Test Hospital 8181818181", hospitals.get(0).getHospitalName());
		assertEquals("Test Hospital 9191919191", hospitals.get(1).getHospitalName());
		assertEquals("Test Hospital 1", hospitals.get(2).getHospitalName());
	}
	
	public void testGetOfficeVisit() throws iTrustException {
		OfficeVisitBean ovb = action.getOfficeVisit();
		assertEquals(1l, action.getOvID());
		assertEquals("Generated for Death for Patient: 1", ovb.getNotes());
		assertEquals(9000000000l, ovb.getHcpID());
		assertEquals(1l, ovb.getID());
		assertEquals(1, ovb.getVisitID());
		assertEquals(0, ovb.getDiagnoses().size());
		assertEquals("1", ovb.getHospitalID());
		assertEquals(0, ovb.getPrescriptions().size());
	}
	
	public void testUpdateInformationEmptyForm() throws SQLException {
		try {
			EditOfficeVisitForm frm = new EditOfficeVisitForm();
			action.updateInformation(frm);
			fail("should have thrown exception");
		} catch (FormValidationException fve) {
		}
	}
	
	public void testUpdateInformation() throws FormValidationException, SQLException {
		EditOfficeVisitForm frm = new EditOfficeVisitForm();
		frm.setHcpID("9000000000");
		frm.setPatientID("1");
		frm.setVisitDate("05/02/2001");
		frm.setAddDiagID("79.3");
		action.updateInformation(frm);
	}
	
	public void testUpdateInformationSemicolon() throws FormValidationException, SQLException {
		EditOfficeVisitForm frm = new EditOfficeVisitForm();
		frm.setHcpID("9000000000");
		frm.setPatientID("1");
		frm.setVisitDate("05/02/2001");
		frm.setNotes("semicolon test ;");
		action.updateInformation(frm);
	}
	
	public void testUpdateInformationOctothorpe() throws Exception {
		EditOfficeVisitForm frm = new EditOfficeVisitForm();
		frm.setHcpID("9000000000");
		frm.setPatientID("1");
		frm.setVisitDate("05/02/2001");
		frm.setNotes("semicolon test #");
		try {
			action.updateInformation(frm);
		} catch (FormValidationException e) {
			fail(e.getMessage());
		}		
	}
	
	public void testCheckAddPrescription() throws FormValidationException, SQLException {
		EditOfficeVisitForm frm = new EditOfficeVisitForm();
		frm.setHcpID("9000000000");
		frm.setPatientID("1");
		frm.setVisitDate("05/02/2001");
		frm.setAddMedID("5");
		frm.setDosage("5");
		frm.setStartDate("02/02/2007");
		frm.setEndDate("02/02/2008");
		frm.setOvID("9000000000");
		
		try {
			frm.setOverrideCode(null);
			fail();
		} catch(FormValidationException e) {
			
		}
		
		String[] overrideCodes = {"00001", "00002"};
		frm.setOverrideCode(overrideCodes);
		frm.setOverrideComment("Other reasons");
		action.updateInformation(frm);
	}	
	
	public void testCheckRemoveSubaction() throws FormValidationException, SQLException {
		EditOfficeVisitForm frm = new EditOfficeVisitForm();
		frm.setHcpID("9000000000");
		frm.setPatientID("1");
		frm.setVisitDate("05/02/2001");
		frm.setAddDiagID("35");
		frm.setRemoveDiagID("35");
		action.updateInformation(frm);
	}
	
	/**
	 * Tests adding a prescription with no allergy
	 * @throws FormValidationException
	 * @throws Exception
	 */
	public void testNoAllergyPrescribe() throws FormValidationException, Exception {
		gen.patient2();
		gen.officeVisit2();
		assertTrue(action2.hasInteraction("081096", "2","2009/9/22","2009/9/22")=="");
		
		//Scenario 3 hw3_part2
		gen.clearAllTables();
		gen.hw3();
		gen.standardData();
		
		EditOfficeVisitAction action = new EditOfficeVisitAction(factory, 9000000003L, "5", "1031");
		EditOfficeVisitForm frm = new EditOfficeVisitForm();
		frm.setHcpID("9000000003"); //gandolf stormcrow
		frm.setPatientID("5"); //baby programmer
		frm.setAddMedID("664662530");
		frm.setDosage("150");
		
		DateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
		Date dat = new Date();
		Calendar c1 = Calendar.getInstance();
		c1.setTime(dat);
		c1.add(c1.DATE, -1);
		
		frm.setVisitDate(dateFormat.format(c1.getTime()));
		
		c1.add(c1.DATE, 22);
		
		frm.setStartDate(dateFormat.format(dat)); //today's date 
		frm.setEndDate(dateFormat.format(c1.getTime())); //21 days from now
		
		frm.setInstructions("Take once daily with water");
		assertEquals("success", action.updateInformation(frm));
	}
	
	public void testInteraction() throws FormValidationException, Exception {
		gen.officeVisit3();
		gen.ndCodes1();
		gen.drugInteractions3();
		assertFalse(action2.hasInteraction("619580501", "1","9/22/2009","10/11/2009")=="");
		
	}
	
	/**
	 * Tests branches of the hasInteraction method
	 * @throws Exception
	 */
	public void testInteractionBranch() throws Exception {
		gen.hw3();
		assertFalse(action2.hasInteraction("081096", "1", "01/26/2011", "02/05/2011") =="");
	}
	
	public void testMakeEmailApp() throws FormValidationException, Exception {
		gen.patient2();
		gen.hcp0();
		Email testEmail = action.makeEmailApp(9000000000L, "2", "You are allergic.");
		assertEquals("no-reply@itrust.com",testEmail.getFrom());
		assertEquals("andy.programmer@gmail.com",testEmail.getToListStr());	
		assertEquals("HCP has prescribed you a potentially dangerous medication",testEmail.getSubject());
		assertEquals("Kelly Doctor has prescribed a medication that you are allergic to or that has a known interaction with a drug you are currently taking. You are allergic.",testEmail.getBody());
	}
	
	public void testIsAllergyOnList()  throws Exception {
		gen.patient2();
		assertEquals("Allergy: Penicillin. First Found: 06/04/2007", action2.isAllergyOnList("2", "664662530"));
	}
	
	public void testIsAllergyOnListWithBadPatientID()  throws Exception {
		gen.patient2();
		try{
			action2.isAllergyOnList("2", "4");
			action2.isAllergyOnList("a", "4");
			fail("Patient does not follow long format!!!!");
		}catch(Exception e){
			e.printStackTrace();
		}
		
		
	}
	
	/**
	 * Test Edit Diagnosis
	 * 
	 * Adds a diagnosis to an office visit
	 * hw3 - scenario 1
	 * @throws IOException 
	 * @throws SQLException 
	 * @throws FileNotFoundException 
	 */
	public void testAddDiagnosis() throws Exception {
		gen.hw3();
		gen.patient1();
		gen.hcp_diagnosis_data();
		
		action3 = new EditOfficeVisitAction(factory, 9000000008L, "1", "1"); //Antonio Medico
		
		EditOfficeVisitForm frm = new EditOfficeVisitForm();
		frm.setHcpID("9000000008"); //Antonio Medico
		frm.setPatientID("1"); //Andy Programmer
		
		DateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
		Date date = new Date();
		
		frm.setVisitDate(dateFormat.format(date)); //today's date
		frm.setNotes("Showing signs of dehydration");
		frm.setAddDiagID("79.10"); //echovirus
		assertEquals("79.10", frm.getAddDiagID());
		//updates successfully
		assertEquals("success", action3.updateInformation(frm));
	}
	
	/**
	 * Cancel a Medical Interaction Alert
	 * hw3-scenario 2
	 */
	public void testCancelMedicalInteraction() throws Exception{
		
		gen.hw3();
		gen.patient2();
		
		action4 = new EditPrescriptionAction(factory);		
		
		assertTrue(action4.hasInteraction("081096", "2", "02/01/2011", "01/15/2011") =="");
		//err...then we cancel
		
	}
	
	/**
	 * Test Edit Diagnosis
	 * 
	 * Adds a diagnosis to an office visit
	 * hw3 - scenario 3
	 * @throws IOException 
	 * @throws SQLException 
	 * @throws FileNotFoundException 
	 */
	public void testEditPrescription() throws Exception {
		gen.hw3();
		gen.patient1();
		gen.hcp_diagnosis_data();
		
		action4 = new EditPrescriptionAction(factory); 
		
		OfficeVisitDAO ovd = new OfficeVisitDAO(factory);
		OfficeVisitBean ovb = ovd.getOfficeVisit(12);
		
		PrescriptionBean pres = ovb.getPrescriptions().get(0);
		pres.setDosage(1000);
		pres.setInstructions("Take as many as you want");
		
		action4.editPrescription(pres);
		
		//check that updates took
		assertEquals("Take as many as you want", ovd.getOfficeVisit(12).getPrescriptions().get(0).getInstructions());
		assertTrue(1000 == ovd.getOfficeVisit(12).getPrescriptions().get(0).getDosage());
	}
	
	/**
	 * HW3-Scenario 4
	 * Tests prescribing a medication with an interaction
	 */
	public void testPrescribeMedsWithInteraction() throws Exception{
		gen.hw3();
		gen.patient2();
		
		action4 = new EditPrescriptionAction(factory);		
		
		assertTrue(action4.hasInteraction("678771191", "2", "02/01/2011", "02/26/2011") =="");
		
		OfficeVisitMedicationDAO ovmDAO = TestDAOFactory.getTestInstance().getOVMedicationDAO();
		
		PrescriptionBean pres = new PrescriptionBean();
		pres.setVisitID(961);
		pres.setDosage(400);
		pres.setMedication(new MedicationBean("678771191", "Ibuprofen"));
		pres.setStartDateStr("02/02/2011");
		pres.setEndDateStr("02/16/2011");
		pres.setInstructions("Take once daily");
		
		long id = ovmDAO.addPrescription(pres);
		
		OverrideReasonBean orb = new OverrideReasonBean("00006");
		orb.setPresID(id);
		ovmDAO.addReason(orb);
		
		assertTrue(ovmDAO.getOverrideReasons(id).size() > 0 );
		//Code to check that email was sent		
		
	}
	
	/**
	 * HW3-Black Box Freeform #1
	 */
	public void testRemoveDiagnosis() throws Exception{
		gen.clearAllTables();
		gen.standardData();
		
		OfficeVisitDAO ovDAO = TestDAOFactory.getTestInstance().getOfficeVisitDAO();
		
		OfficeVisitBean ob = ovDAO.getOfficeVisit(11);
		
		assertEquals( 1, ob.getDiagnoses().size());
		
		OfficeVisitDiagnosisDAO ovdDAO = TestDAOFactory.getTestInstance().getOVDiagnosisDAO();
		
		ovdDAO.removeDiagnosisFromOfficeVisit(ob.getDiagnoses().get(0).getOvDiagnosisID());
		
		ob = ovDAO.getOfficeVisit(11);
		
		assertEquals( 0, ob.getDiagnoses().size());
		
	}
	
	/**
	 * Black box free form #2
	 * @throws Exception
	 */
	public void testRemoveExisitingPrescription() throws Exception{
		gen.clearAllTables();
		gen.standardData();
				
		OfficeVisitDAO ovDAO = TestDAOFactory.getTestInstance().getOfficeVisitDAO();
		
		OfficeVisitBean ob = ovDAO.getOfficeVisit(955);
		
		assertEquals( 3, ob.getPrescriptions().size());
		
		OfficeVisitMedicationDAO ovmDAO = TestDAOFactory.getTestInstance().getOVMedicationDAO();
		
		ovmDAO.removePrescription(ob.getPrescriptions().get(0).getId());
		
		ob = ovDAO.getOfficeVisit(955);
		
		assertEquals( 2, ob.getPrescriptions().size());
		
	}
	
	
	/**
	 * Black box free form #3
	 * @throws Exception
	 */
	public void testAddLabProceduretoExisting() throws Exception{
		gen.clearAllTables();
		gen.standardData();
				
		LabProcedureDAO lpDAO = TestDAOFactory.getTestInstance().getLabProcedureDAO();
		assertEquals( 2, lpDAO.getAllLabProceduresForDocOV(955).size());
		LabProcedureBean b = new LabProcedureBean();
		b.setLoinc("13495-7");
		b.setOvID(955);
		b.setPid(2);
		b.setProcedureID(300);
		b.setLtID(5000000000L);
		lpDAO.addLabProcedure(b);
		assertEquals( 3, lpDAO.getAllLabProceduresForDocOV(955).size());		
	}
	
	
	/**
	 * Black box free form #4
	 * @throws Exception
	 */
	public void testRemoveLabProcedureFromExisting() throws Exception{
		gen.clearAllTables();
		gen.standardData();
				
		OfficeVisitLabProcedureDAO ovlpDAO = TestDAOFactory.getTestInstance().getOVLabProcedureDAO();
		LabProcedureDAO lpDAO = TestDAOFactory.getTestInstance().getLabProcedureDAO();
		assertEquals( 2, lpDAO.getAllLabProceduresForDocOV(955).size());
		ovlpDAO.removeLabProcedureFromOfficeVisit(lpDAO.getAllLabProceduresForDocOV(955).get(0).getProcedureID());
		assertEquals( 1, lpDAO.getAllLabProceduresForDocOV(955).size());
	}
	
	/**
	 * Black box free form #5
	 * @throws Exception
	 */
	public void testRemoveImmunizationFromExisting() throws Exception{
		gen.clearAllTables();
		gen.standardData();
				
		OfficeVisitDAO ovDAO = TestDAOFactory.getTestInstance().getOfficeVisitDAO();
		OfficeVisitBean ob = ovDAO.getOfficeVisit(1000);
		assertEquals( 1, ob.getProcedures().size());
		OfficeVisitProcedureDAO ovpDAO = TestDAOFactory.getTestInstance().getOVProcedureDAO();
		ovpDAO.removeProcedureFromOfficeVisit(ob.getProcedures().get(0).getOvProcedureID());
		ob = ovDAO.getOfficeVisit(1000);
		assertEquals( 0, ob.getProcedures().size());		
	}
	
	/**
	 * Test Patient Referral
	 */
	public void testPatientReferral() throws Exception {
		gen.clearAllTables();
		gen.standardData();
		
		PatientReferralBean b = new PatientReferralBean();
		PatientReferralBean c = new PatientReferralBean();
		PatientReferralAction action1 = new PatientReferralAction(factory, 9000000001L);
		action1.sendReferral(b);
		action1.sendReferral(c);
		action1.deleteReferral(b);
		action1.getReferral(1);
		action1.getReferralsForOfficeVisit(1);
		action1.getReferralsForPatient(1L);
		action1.getReferralsSentFromMe();
		action1.getReferralsSentToMe();
		action1.sort("", "", "1");
		action1.sort("name", "", "");
		action1.sort("hcp", "", "");
		action1.sort("priority", "", "");
		action1.sort("time", "", "");
		action1.sort("name", "asce", "");
		action1.sort("hcp", "asce", "");
		action1.sort("priority", "asce", "");
		action1.sort("time", "asce", "");
		
		EditOfficeVisitForm frm = new EditOfficeVisitForm();
		frm.setHcpID("9000000000");
		frm.setPatientID("1");
		frm.setVisitDate("05/02/2001");
		frm.setReferTo("9000000001");
		frm.setReferNotes("yo");
		action.updateInformation(frm);
	}
	
	/**
	 * Test
	 */
	public void testOthers() throws Exception {
		gen.clearAllTables();
		gen.standardData();
		
		OfficeVisitDiagnosisDAO ovdDAO = TestDAOFactory.getTestInstance().getOVDiagnosisDAO();
		long ovDID = ovdDAO.addDiagnosisToOfficeVisit(250.1, 1);
		DiagnosisBean diag = new DiagnosisBean("250.3", "", "");
		diag.setOvDiagnosisID(ovDID);
		diag.setVisitID(1);
		action.editDiagnosis(diag);
		
		OfficeVisitProcedureDAO ovpDAO = TestDAOFactory.getTestInstance().getOVProcedureDAO();
		long ovPID = ovpDAO.addProcedureToOfficeVisit("1", 1, "1");
		List<ProcedureBean> procedure = ovpDAO.getProcedures(1);
		ProcedureBean proc = new ProcedureBean("250.3", "", "");
		action.editProcedure(proc);
		
		OfficeVisitLabProcedureDAO ovlpDAO = TestDAOFactory.getTestInstance().getOVLabProcedureDAO();
		long ID = ovlpDAO.addLabProcedureToOfficeVisit("1", 1, 1);
		LabProcedureBean lpb = new LabProcedureBean();
		lpb.setCommentary("1");
		lpb.setLoinc("1");
		lpb.setOvID(1);
		lpb.setPid(1);
		lpb.setLtID(1);
		action.completeProcedure("1", "1");
		action.addLabProcedure(lpb);
		action.updateAssignedTech("1", 1);
		
	}
}
